package libtool65.o65;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;

public class Mode {
//	mode.15 :	CPU	0= 6502 	1= 65816
	private final static int CPU_FLAG = 0x8000;  
//	mode.14	:	reloc	0= bytewise... 	1= page(256byte)wise relocation
//						   allowed
	private final static int PAGE_FLAG = 0x4000;
//	mode.13	:	size	0= size=16 bit,	1= size=32 bit
	private final static int SIZE_FLAG = 0x2000;
//	mode.12 :	obj	0= executable	1= object file
	private final static int OBJECT_FLAG = 0x1000;
//	mode.11 :	simple	0= (ignored)	1= simple file addresses
	private final static int SIMPLE_FLAG = 0x0800;
//	mode.10 :	chain	0= (ignored)	1= another file follows this one
	private final static int CHAIN_FLAG = 0x0400;
//	mode.9  :	bsszero 0= (ignored)	1= the bss segment must be zeroed out for this file
	private final static int BSSZERO_FLAG = 0x0200;
//	mode.4-7 :	CPU2	0000 = 6502 core (no undocumented opcodes)
//				0001 = 65C02 /w some bugfix, no illegal opcodes
//				0010 = 65SC02 (enhanced 65C02), some new opcodes
//				0011 = 65CE02 some 16bit ops/branches, Z register is modifiable
//				0100 = NMOS 6502 (including undocumented opcodes)
//				0101 = 65816 in 6502 emulation mode
//				011x = reserved
//				1xxx = reserved
//				^^^^ 
//				|||+- Bit 4
//				||+-- Bit 5
//				|+--- Bit 6
//				+---- Bit 7
	private final static int CPU2_MASK = 0x00F0;
	private final static int CPU2_6502 = 0x0000;
	private final static int CPU2_65C02 = 0x0010;
	private final static int CPU2_65SC02 = 0x0020;
	private final static int CPU2_65CE02 = 0x0030;
	private final static int CPU2_NMOS6502 = 0x0040;
	private final static int CPU2_65816 = 0x0050;
//	mode.0-1:	align	0= byte align,	
//				1= word (i.e. 2 byte) align
//				2= long (4 byte) align
//				3= block (256 byte) align
	private final static int ALIGN_MASK = 0x0003;
	
	private int mode;

	public void read(InputStream file) throws IOException {
		mode = file.read();
		mode |= file.read() << 8;
	}

	public int readSize(InputStream file) throws IOException {
		int size = file.read();
		size |= file.read() << 8;
		if (isLongSize())
		{
			size |= file.read() << 16;
			size |= file.read() << 24;
		}
		return size;
	}

	public void dumpInfo(PrintStream out) {
		out.println("Mode: "+mode);
		if (isSuperCpu())
			out.println("  65816");
		else
			out.println("  6502");
		if (isPageRealloc())
			out.println("  PAGE REALLOC");
		else
			out.println("  BYTE REALLOC");
		if (isLongSize())
			out.println("  SIZE 32bit");
		else
			out.println("  SIZE 16bit");
		if (isObjectFlag())
			out.println("  OBJECT");
		else
			out.println("  EXE");
		if (isSimple())
			out.println("  SIMPLE");
		if (isChain())
			out.println("  CHAIN");
		if (isBssZero())
			out.println("  BSS ZERO");
		out.print("  CPU(2) ");
		switch (mode & CPU2_MASK)
		{
		case CPU2_6502: out.println("6502"); break;
		case CPU2_65C02: out.println("65C02"); break;
		case CPU2_65SC02: out.println("65SC02"); break;
		case CPU2_65CE02: out.println("65CE02"); break;
		case CPU2_NMOS6502: out.println("NMOS 6502"); break;
		case CPU2_65816: out.println("65816/6502"); break;
		default: out.println("UNKNOWN"); break;
		}
		out.println("  ALIGN "+(mode & ALIGN_MASK));
	}

	public boolean isBssZero() {
		return (mode & BSSZERO_FLAG) != 0;
	}

	public boolean isChain() {
		return (mode & CHAIN_FLAG) != 0;
	}

	public boolean isSimple() {
		return (mode & SIMPLE_FLAG) != 0;
	}

	public boolean isObjectFlag() {
		return (mode & OBJECT_FLAG) != 0;
	}

	public boolean isPageRealloc() {
		return (mode & PAGE_FLAG) != 0;
	}

	public boolean isSuperCpu() {
		return (mode & CPU_FLAG) != 0;
	}

	public boolean isLongSize() {
		return (mode & SIZE_FLAG) != 0;
	}
}
